﻿package com._public._utils._mailer
{
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	
	public class Mailer extends EventDispatcher implements IMailer
	{
		
		public function Mailer() {
			
		}
		
		/**
		 * 邮箱登录名 
		 */		
		protected var userName:String;
		
		/**
		 * 邮箱登陆密码 
		 */		
		protected var password:String;
		
		/**
		 * 这是邮箱登陆用户名及密码
		 *  
		 * @param userName
		 * @param password
		 * 
		 */		
		public function setPassport(userName:String, password:String):void {
			this.userName = userName;
			this.password = password;
		}
		
		
		/**
		 * SMTP服务地址 
		 */		
		protected var smtpHost:String;
		
		/**
		 * SMTP服务端口 
		 */		
		protected var smtpPort:uint = 25;
		
		
		/**
		 * 设置smtp
		 *  
		 * @param host
		 * @param port
		 * 
		 */		
		public function setSMTP(host:String, port:uint = 25):void {
			smtpHost = host;
			smtpPort = port;
		}
		
		
		/**
		 * 设置pop3
		 * 
		 * @param host
		 * @param port
		 * 
		 */		
		public function setPOP3(host:String, port:uint = 110):void {
			throw new Error("该方法还没有实现...");
		}
		
		
		/**
		 * 发送邮件
		 *  
		 * @param mail
		 * 
		 */		
		public function sendMail(mail:Mail):void {
			var steps:Array = createSendMailSteps(mail);
			sendSMTPData(steps);
		}
		
		
		/**
		 * 创建邮件发送步骤数据
		 * 
		 * @return Array
		 * 
		 */		
		protected function createSendMailSteps(mail:Mail):Array {
			var steps:Array = [];
			
			steps.push("HELO laan");
			steps.push("AUTH login");
			
			steps.push(Base64.encode(userName));
			
			steps.push(Base64.encode(password));
  			
  			steps.push("MAIL FROM:<" + mail.from + ">");
  			steps.push("RCPT TO:<" + mail.tu + ">");
  			
  			if (mail.cc) {
  				var cc:Array = mail.cc;
  				
  				for(var j:uint = 0; j < cc.length; j++) {
		  			steps.push("RCPT TO:<" + cc[j] + ">");
  				}
  			}
  			
  			steps.push("DATA");
  			
			var mailData:Array = [];
			if (!mail.fromName) {
	  			mailData.push("From:" + mail.from);
			} else {
	  			mailData.push("From:" + mail.fromName);
			}
			
			if (!mail.toName) {
	  			mailData.push("To:" + mail.tu);
			} else {
	  			mailData.push("To:" + mail.toName);
			}
			
  			if (mail.subject) {
  				mailData.push("Subject:" + mail.subject);
  			}
  			
  			if (mail.cc) {
  				mailData.push("CC:" + mail.cc);
  			}
  			
  			if (mail.sender) {
  				mailData.push("Sender:" + mail.sender);
  			}
  			
  			
  			var boundary:String = "laan" + uint(Math.random() * 100000000);
  			
  			mailData.push("MIME-Version:1.0");
			//mailData.push("Content-Type:multipart/related;boundary=QQQQQQQ");
			//mailData.push("Content-Type:multipart/alternative;boundary=QQQQQQQ");
			mailData.push("Content-Type:multipart/mixed;boundary=" + boundary);
			//mailData.push("Content-Transfer-Encoding:7bit");
			
  			mailData.push("");
  			//mailData.push("sdsssss");
  			
  			
			//邮件内容
  			mailData.push("--" + boundary);
			mailData.push("Content-Type:text/html;charset=GBK");
			//mailData.push("Content-Type:text/html;boundary=QQQQQQQ");
			mailData.push("Content-Transfer-Encoding:8bit");
  			mailData.push("");
  			mailData.push(mail.body);
  			
  			/* mailData.push("--QQQQQQQ");
			mailData.push("Content-Type:text/plain;name=aa.txt");
			//mailData.push("Content-Transfer-Encoding:7bit");
  			mailData.push("");
  			mailData.push(mail.body); */
  			
  			//mailData.push("--QQQQQQQ--");
			//mailData.push("Content-Type:multipart/mixed;boundary=QQQQQQQ");
			
  			var attachments:Array = mail.attachments;
			if (attachments && attachments.length > 0) {
				
				//mailData.push("Content-Type:multipart/mixed");
				
	  			for (var i:uint = 0; i < attachments.length; i++) {
	  				var attach:Attachment = attachments[i];
	  				
	  				//if (i != 0) 
	  				mailData.push("--" + boundary);
	  				mailData.push("Content-Type:application/octet-stream;name=" + attach.name);
					mailData.push("Content-Transfer-Encoding:base64");
					
					//判断附件是否是作为内嵌资源发送
					if (attach.isInline()) {
						mailData.push("Content-Disposition:inline");
						mailData.push("Content-ID:<" + attach.contentId +">");
					} else {
						mailData.push("Content-Disposition:attachment");
					}
					
					mailData.push("");
					mailData.push(attach.data);
		  			
	  			}
  				//mailData.push("--" + boundary + "--");
  			}
  			
  			mailData.push("--" + boundary + "--");
  			
  			mailData.push("");
  			mailData.push(".");
  			mailData.push("");
  			
  			steps.push(mailData);
  			steps.push("QUIT");
  			
  			return steps;
		}
		
		
		//=======================================================================================
		//SMTP
		//=======================================================================================
		/**
		 * smtp数据发送器 
		 */		
		private var smtpSender:Socket;
		
		
		private var steps:Array;
		
		private var stepIndex:uint;
		
		/**
		 * 发送SMTP序列数据
		 *  
		 * @return 
		 * 
		 */		
		private function sendSMTPData(steps:Array):void {
			this.steps = steps;
			stepIndex = 0;
			
			smtpSender = new Socket();
	        addSMTPSenderHandlers();
	        smtpSender.connect(smtpHost, smtpPort);
		}
		
		
		private function addSMTPSenderHandlers():void {
			smtpSender.addEventListener(Event.CLOSE, closeHandler);
	        smtpSender.addEventListener(Event.CONNECT, connectHandler);
	        smtpSender.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
	        smtpSender.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
	        smtpSender.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
		}
		
		private function removeSMTPSenderHandlers():void {
			if(smtpSender==null)return;
			smtpSender.removeEventListener(Event.CLOSE, closeHandler);
	        smtpSender.removeEventListener(Event.CONNECT, connectHandler);
	        smtpSender.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
	        smtpSender.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
	        smtpSender.removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
	        
	        try {
	        	smtpSender.close();
	        } catch (e:Error) {
	        	
	        }
	        
	        smtpSender = null;
		}
		
		private function writeln(str:*):void {
	        try {
	        	//设置字符集为‘gb2312’
	        	if (str is String) {
			        trace((str as String).substr(0, 2000));
			        str += "\r\n";
	            	smtpSender.writeMultiByte(str, "gb2312");
	         	} else if (str is ByteArray){
	         		var bytes:ByteArray = str as ByteArray;
	         		trace("***********************");
	         		trace("bytes length:" + bytes.length);
	         		trace("***********************");
	         		smtpSender.writeBytes(bytes, 0, bytes.length);
	         	} else {
	         		smtpSender.writeObject(str);
	         	}
	            //writeUTFBytes(str);
	            //writeUTF(str);
	        }
	        catch(e:IOError) {
	        	trace(e);
	            dispatchEvent(new MailEvent(MailEvent.SOCKET_IO_ERROR));
	        }
	    }
		
	    /**
	     * 发送数据
	     * @param request
	     * 
	     */	
	    private function sendRequest(request:*):void {
	        writeln(request);
	        smtpSender.flush();
	    }
		
		/**
		 * 读取数据
		 */
	     private function readResponse():void {
	        var str:String = smtpSender.readMultiByte(smtpSender.bytesAvailable, "gb2312");
	        trace("SMTP response:" + str);
	        
	        decode(str);
	    }
	    
	    /**
	     * 解析服务器返回的数据并发送相应数据 
	     * @param response 服务器数据
	     * 
	     */
	    private function decode(response:String):void {
	    	var code:int = parseInt(response.substr(0, 3));
	    	
	    	/* 
			rightcodeht.add("220","服务就绪");
			rightcodeht.add("221","服务关闭传输信道");
			rightcodeht.add("334","服务器响应验证base64字符串");
			rightcodeht.add("235","验证成功"); 
			rightcodeht.add("250","要求的邮件操作完成");
			rightcodeht.add("251","用户非本地，将转发向<forward-path>");
			rightcodeht.add("354","开始邮件输入，以<enter>.<enter>结束");
			errcodeht.add("421","服务未就绪，关闭传输信道");
			errcodeht.add("432","需要一个密码转换");
			errcodeht.add("450","要求的邮件操作未完成，邮箱不可用（例如，邮箱忙）");
			errcodeht.add("451","放弃要求的操作；处理过程中出错");
			errcodeht.add("452","系统存储不足，要求的操作未执行");
			errcodeht.add("454","临时认证失败");
	    	errcodeht.add("500","邮箱地址错误");
			errcodeht.add("501","参数格式错误");
			errcodeht.add("502","命令不可实现");
			errcodeht.add("503","服务器需要smtp验证");
			errcodeht.add("504","命令参数不可实现");
			errcodeht.add("530","需要认证"); 
			errcodeht.add("534","认证机制过于简单");
			errcodeht.add("538","当前请求的认证机制需要加密");
			errcodeht.add("550","要求的邮件操作未完成，邮箱不可用（例如，邮箱未找到，或不可访问）");
			errcodeht.add("551","用户非本地，请尝试<forward-path>");
			errcodeht.add("552","过量的存储分配，要求的操作未执行");
			errcodeht.add("553","邮箱名不可用，要求的操作未执行（例如邮箱格式错误）");
			 */
			
	    	if (code == 220 ||//HELO
	    		code == 250 ||
	    		code == 235 ||//Authentication successful
	    		code == 334 ||//授权验证
	    		code == 354) {
	    		
	    		var stepInfo:* = steps[stepIndex++];
	    		
	    		if (stepInfo is Array) {
	    			var infos:Array = stepInfo as Array;
	    			
	    			for (var i:uint = 0; i < infos.length; i++) {
	    				sendRequest(infos[i]);
	    			}
	    		} else if (stepInfo is String) {
	    			sendRequest(stepInfo);
	    		} else {
	    			return;
	    		}
	    		
	    		dispatchEvent(new MailEvent(MailEvent.MAIL_INFO, response.substr(4, response.length)));
	    		dispatchEvent(new MailEvent(MailEvent.MAIL_STEP, stepInfo));
	    		
	    		return;
	    	}
	    	
	    	
	    	if (code == 502 ||
	    		code == 500 ||//语法错误，命令不能识别
	    		code == 550 ||//命令不能执行，邮箱无效
	    		code == 552 ||//中断处理：用户超出文件空间
	    		code == 535 ||//authentication failed
	    		code == 450 ||
	    		code == 504 ||
	    		code == 553) //Sender address rejected: not owned by user
	    	{
	    		
	    		var serverInfo:String = response.substr(4, response.length);
	    		dispatchEvent(new MailEvent(MailEvent.MAIL_ERROR, serverInfo));
	    		
	    		return;
	    	}
	    }
	
	    private function closeHandler(event:Event):void {
	    	removeSMTPSenderHandlers();
	    	
	        dispatchEvent(new MailEvent(MailEvent.SOCKET_QUIT));
	    }
	
	    private function connectHandler(event:Event):void {
	        dispatchEvent(new MailEvent(MailEvent.SOCKET_CONNECTED));
	    }
	
	    private function ioErrorHandler(event:Event):void {
	    	removeSMTPSenderHandlers();
	    	
	        dispatchEvent(new MailEvent(MailEvent.SOCKET_IO_ERROR));
	    }
	
	    private function securityErrorHandler(event:Event):void {
	    	removeSMTPSenderHandlers();
	    	
	        dispatchEvent(new MailEvent(MailEvent.SOCKET_SECURITY_ERROR));
	    }
	
	    private function socketDataHandler(event:ProgressEvent):void {
	        dispatchEvent(new MailEvent(MailEvent.SOCKET_DATA));
	        readResponse();
	    }
	    //=================================================================================================
	}
}